#include "dialog.h"
#include "ui_dialog.h"
#include <QString>
#include "gy33streamparser.h"
#include <QThread>
#include <QSerialPort>
//#include <qDebug>
#include <QSettings>
#include <QFileInfo>
#include <math.h>

unsigned char data1[] = {0x5A, 0x5A, 0x15, 0x08, 0x01, 0x78, 0x01, 0x92, 0x00, 0x4C, 0x05, 0x05, 0x33};
unsigned char data2[] = {0x5A, 0x5A, 0x25, 0x06, 0x02, 0xCC, 0x0C, 0x5D, 0x00, 0x02, 0x18};
unsigned char data3[] = {0x5A, 0x5A, 0x45, 0x03, 0xFF, 0xFF, 0x4C, 0x46};
unsigned char data4[] = {0x5A, 0x5A, 0x55, 0x03, 0x0C};

//char *pMarkName[] = {"0", "0.5", "1.0", "1.5", "2.0", "2.5", "3.0"};
//char *pMarkName[] = {"5", "10", "15", "20", "30", "40"};
char *pMarkName[] = {"0", "40", "50", "100", "1000", "3000"};
int markValue[20][3] = {};

void data_process(unsigned char code, const unsigned char *value,
                          unsigned char numBytes, void *customData)

{
//    QString str = "data:";
//    for(int i=0; i<numBytes; i++)
//    {
//        QString tmp;
//        tmp.sprintf("0x%02X, ", value[i]);
//        str += tmp;
//    }
//    qDebug("code:%02X numBytes:%d", code, numBytes);
//    qDebug("%s", str.toStdString().c_str());


    Dialog *handle = (Dialog *)customData;

    if(handle == NULL)
        return;

    if(code == PARSER_CODE_RAWRGB)
    {
        unsigned int raw_R, raw_G, raw_B, raw_C, raw_Gray;

        raw_R = (value[0]<<8) | value[1];
        raw_G = (value[2]<<8) | value[3];
        raw_B = (value[4]<<8) | value[5];
        raw_C = (value[6]<<8) | value[7];

        raw_Gray = (unsigned int)(raw_R*0.299 + raw_G*0.587 + raw_B*0.114);

//        qDebug("raw_R:%d raw_G:%d raw_B:%d raw_C:%d", raw_R, raw_G, raw_B, raw_C);
        handle->setRGBY(raw_R, raw_G, raw_B, raw_Gray);
        handle->setRawC(raw_C);

    }
    else if(code == PARSER_CODE_LTSC)
    {
        unsigned int Lux, CT, Color;

        Lux = (value[0]<<8) | value[1];
        CT = (value[2]<<8) | value[3];
        Color = (value[4]<<8) | value[5];

//        qDebug("Lux:%d CT:%d Color:%d", Lux, CT, Color);
    }
    else if(code == PARSER_CODE_PROCESSRGB)
    {
        unsigned int R, G, B, Gray;

        R = value[0];
        G = value[1];
        B = value[2];

        Gray = (unsigned int)(R*0.299 + G*0.587 + B*0.114);

//        qDebug("R:%d G:%d B:%d Gray:%d", R, G, B, Gray);
//        handle->setRGBY(R, G, B, Gray);
    }
}


processThread::processThread(Dialog *handle)
{
    m_handle = handle;
}


void processThread::run()
{
    void *handle = GY33_initParser(data_process, m_handle);
    QSerialPort *serial = new QSerialPort();
    serial->setPortName(((Dialog *)m_handle)->m_uartDev);
    serial->setBaudRate(QSerialPort::Baud9600);
    serial->setParity(QSerialPort::NoParity);
    serial->setDataBits(QSerialPort::Data8);
    serial->setStopBits(QSerialPort::OneStop);
    serial->setFlowControl(QSerialPort::NoFlowControl);
    if (serial->open(QIODevice::ReadWrite))
    {
//        qDebug()<<"open success";
        const unsigned char ledMax[3] = {0xA5, 0x60, 0x05};
        serial->write((const char *)ledMax, sizeof(ledMax));
        while(1)
        {
            if(serial->waitForReadyRead(100) == true)
            {
                QByteArray data;
                data = serial->readAll();

                for(int i=0; i<data.size(); i++)
                    GY33_parseByte(handle, data.data()[i]);
            }
        }
    } else
    {
//        qDebug()<<"open failed";
    }


}

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);


//    {
//        double temperature = 0;
//        double RT = 0;
//        const double B=3949;
//        const double TN=273.15+37;//常温
//        const double RN=30.218;//常温对应的阻值，注意单位是千欧

//        RT = RN + RN*0.05/100;
//        temperature = 1/(1/TN + log(RT/RN)/B)-273.15;
//        qDebug("%f", temperature);

//        RT = RN - RN*0.05/100;
//        temperature = 1/(1/TN + log(RT/RN)/B)-273.15;
//        qDebug("%f", temperature);
//    }

    {
        double adcValue0MicroVolt, adcVDDSMicroVolt;
        double RT1 = 0;
        double RT2 = 0;


        adcValue0MicroVolt = 0.635;
        adcVDDSMicroVolt = 1.27;

        RT1 = 30.0*adcValue0MicroVolt/(adcVDDSMicroVolt-adcValue0MicroVolt);


        adcValue0MicroVolt = adcValue0MicroVolt + (1.4785/4096);
        adcVDDSMicroVolt = 1.27;

        RT2 = 30.0*adcValue0MicroVolt/(adcVDDSMicroVolt-adcValue0MicroVolt);

        qDebug("%f %f %f", RT1, RT2, RT2-RT1);

        double temperature1 = 0;
        double temperature2 = 0;
        double RT = 0;
        const double B=3949;
        const double TN=273.15+37;//常温
        const double RN=30.218;//常温对应的阻值，注意单位是千欧

        RT = RT1;
        temperature1 = 1/(1/TN + log(RT/RN)/B)-273.15;
        qDebug("%f", temperature1);

        RT = RT2;
        temperature2 = 1/(1/TN + log(RT/RN)/B)-273.15;
        qDebug("%f", temperature2);

        qDebug("%f", temperature1 - temperature2);
    }


    for(int i=0; i<sizeof(pMarkName)/sizeof(pMarkName[0]); i++)
    {
        ui->comboBox_name->addItem(pMarkName[i]);
    }

    QString iniFileName = QCoreApplication::applicationDirPath() + "//GLU_config.ini";
    QFileInfo fileInfo(iniFileName);
    if(fileInfo.exists() == true)
    {
        QSettings configIniRead(iniFileName, QSettings::IniFormat);

        m_uartDev = configIniRead.value("dev/name").toString();

        for(int i=0; i<sizeof(pMarkName)/sizeof(pMarkName[0]); i++)
        {
            QString strName(pMarkName[i]);
            markValue[i][0] = configIniRead.value(strName+"/R").toInt();
            markValue[i][1] = configIniRead.value(strName+"/G").toInt();
            markValue[i][2] = configIniRead.value(strName+"/B").toInt();
        }
    }
    else
    {
        QString iniFileName = QCoreApplication::applicationDirPath() + "//GLU_config.ini";


        QSettings configIniWrite(iniFileName, QSettings::IniFormat);
        configIniWrite.setValue("dev/name", "/dev/ttyUSB0");
        m_uartDev = "/dev/ttyUSB0";
    }


    m_proThread = new processThread(this);

    m_proThread->start();

    move(0, 0);
}

Dialog::~Dialog()
{
    delete ui;
}

typedef struct {
    double r;       // a fraction between 0 and 1
    double g;       // a fraction between 0 and 1
    double b;       // a fraction between 0 and 1
} rgb;

typedef struct {
    double h;       // angle in degrees
    double s;       // a fraction between 0 and 1
    double v;       // a fraction between 0 and 1
} hsv;

static hsv rgb2hsv(rgb in)
{
    hsv         out;
    double      min, max, delta;

    min = in.r < in.g ? in.r : in.g;
    min = min  < in.b ? min  : in.b;

    max = in.r > in.g ? in.r : in.g;
    max = max  > in.b ? max  : in.b;

    out.v = max;                                // v
    delta = max - min;
    if (delta < 0.00001)
    {
        out.s = 0;
        out.h = 0; // undefined, maybe nan?
        return out;
    }
    if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash
        out.s = (delta / max);                  // s
    } else {
        // if max is 0, then r = g = b = 0
        // s = 0, h is undefined
        out.s = 0.0;
        out.h = NAN;                            // its now undefined
        return out;
    }
    if( in.r >= max )                           // > is bogus, just keeps compilor happy
        out.h = ( in.g - in.b ) / delta;        // between yellow & magenta
    else
    if( in.g >= max )
        out.h = 2.0 + ( in.b - in.r ) / delta;  // between cyan & yellow
    else
        out.h = 4.0 + ( in.r - in.g ) / delta;  // between magenta & cyan

    out.h *= 60.0;                              // degrees

    if( out.h < 0.0 )
        out.h += 360.0;

    return out;
}

static double distanceOf(int *pValue1, int *pValue2, int size)
{
    hsv hsv1;
    hsv hsv2;
    rgb tmpRGB;
    double R = 100;
    double angle = 30;
    double h = R * cos(angle / 180 * M_PI);
    double r = R * sin(angle / 180 * M_PI);

    tmpRGB.r = pValue1[0];
    tmpRGB.g = pValue1[1];
    tmpRGB.b = pValue1[1];
    hsv1 = rgb2hsv(tmpRGB);

    tmpRGB.r = pValue2[0];
    tmpRGB.g = pValue2[1];
    tmpRGB.b = pValue2[1];
    hsv2 = rgb2hsv(tmpRGB);

    double x1 = r * hsv1.v * hsv1.s * cos(hsv1.h / 180 * M_PI);
    double y1 = r * hsv1.v * hsv1.s * sin(hsv1.h / 180 * M_PI);
    double z1 = h * (1 - hsv1.v);
    double x2 = r * hsv2.v * hsv2.s * cos(hsv2.h / 180 * M_PI);
    double y2 = r * hsv2.v * hsv2.s * sin(hsv2.h / 180 * M_PI);
    double z2 = h * (1 - hsv2.v);
    double dx = x1 - x2;
    double dy = y1 - y2;
    double dz = z1 - z2;
    return sqrt(dx * dx + dy * dy + dz * dz);
}


double O_distance(int *pValue1, int *pValue2, int size)
{
    double fSum = 0;
    for(int i=0; i<size; i++)
    {
        fSum += pow(pValue1[i] - pValue2[i], 2);
    }

    return sqrt(fSum);
}

double Minkowski_Distance(int *pValue1, int *pValue2, int size)
{
    double fSum = 0;
    for(int i=0; i<size; i++)
    {
        fSum += pow(pValue1[i] - pValue2[i], 3);
    }

    return pow(fSum, 1/3);
}

double Cosine(int *pValue1, int *pValue2, int size)
{
    double up = 0;
    double down1 = 1;
    double down2 = 1;

    for(int i=0; i<size; i++)
    {
        up += pValue1[i] * pValue2[i];
        down1 *= pow(pValue1[i], 2);
        down2 *= pow(pValue2[i], 2);
    }

//    for(int i=0; i<size; i++)
//    {
//        down1 *= pValue1[i];
//        down2 *= pValue2[i];
//    }

    down1 = sqrt(down1);
    down2 = sqrt(down2);


    return up/(down1*down2);
}

void Dialog::setRGBY(int R, int G, int B, int Y)
{
    QString tmp;

    m_R = R;
    m_G = G;
    m_B = B;
    m_Y = Y;

    ui->lineEdit_R->setText(tmp.sprintf("%d", m_R));
    ui->lineEdit_G->setText(tmp.sprintf("%d", m_G));
    ui->lineEdit_B->setText(tmp.sprintf("%d", m_B));
    ui->lineEdit_Y->setText(tmp.sprintf("%d", m_Y));

    int nName = 0;
    double fValue = 0;
    int nRGB[3] = {m_R, m_G, m_B};
    for(int i=0; i<sizeof(pMarkName)/sizeof(pMarkName[0]); i++)
    {
        double od = distanceOf(markValue[i], nRGB, 3);
        if(i == 0)
        {
            fValue = od;
            nName = 0;
        }
        else if(fValue > od)
        {
            fValue = od;
            nName = i;
        }
    }

    ui->lineEdit_Name->setText(pMarkName[nName]);

}


void Dialog::setRawC(int RawC)
{
    QString tmp;

    m_RawC = RawC;
    ui->lineEdit_C->setText(tmp.sprintf("%d", m_RawC));
}


void Dialog::on_pushButton_clicked()
{
    QString strName = ui->comboBox_name->currentText();
    QString iniFileName = QCoreApplication::applicationDirPath() + "//GLU_config.ini";


    QSettings configIniWrite(iniFileName, QSettings::IniFormat);
    configIniWrite.setValue(strName+"/R", m_R);
    configIniWrite.setValue(strName+"/G", m_G);
    configIniWrite.setValue(strName+"/B", m_B);

    for(int i=0; i<sizeof(pMarkName)/sizeof(pMarkName[0]); i++)
    {
        QString tmp(pMarkName[i]);
        if(tmp == strName)
        {
            markValue[i][0] = m_R;
            markValue[i][1] = m_G;
            markValue[i][2] = m_B;
        }
    }

}
